package com.example.kekewaimaibao.address.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.kekewaimaibao.address.constant.AddressConstant;
import com.example.kekewaimaibao.address.model.AddressDO;
import com.example.kekewaimaibao.address.service.IAddressService;
import com.example.kekewaimaibao.core.constant.RestConstant;
import com.example.kekewaimaibao.user.model.UserDO;
import com.example.kekewaimaibao.user.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: xuxiang
 * @date: 2022/3/6 22:58 星期日
 * @description: 用户地址控制层
 * @version: 1.0
 */
@Slf4j
@RestController
@RequestMapping(AddressController.PATH)
@Api(tags = "定位控制层")
@CrossOrigin
public class AddressController {

    public static final String PATH = RestConstant.VERSION_V1 + "/address";

    @Autowired
    IAddressService addressService;

    @Autowired
    IUserService userService;

    /**
     * 建议弃用全表查询
     * @return
     */
    @ApiOperation(value = "所有地址列表")
    @GetMapping("/list")
    public R list() {
        List<AddressDO> list = addressService.list(null);
        return R.ok(list);
    }

    /**
     * 可根据省、市、区进行分页，可根据详细地址信息模糊分页
     * @param current 当前页
     * @param limit 每页数据条数
     * @param addressDO 用户地址信息
     * @return
     */
    @ApiOperation(value = "分页查询地址信息")
    @PostMapping("/page/{current}/{limit}")
    public R page(@PathVariable long current, @PathVariable long limit,
                  @RequestBody(required = false) AddressDO addressDO) {
        Page<AddressDO> page = new Page<>(current, limit);
        QueryWrapper<AddressDO> wrapper = null;
        if (ObjectUtil.isNotNull(addressDO)) {
            wrapper = new QueryWrapper<>();
            if (StrUtil.isNotBlank(addressDO.getProvince())) {
                wrapper.eq("province", addressDO.getProvince());
            }
            if (StrUtil.isNotBlank(addressDO.getCity())) {
                wrapper.eq("city", addressDO.getCity());
            }
            if (StrUtil.isNotBlank(addressDO.getDistrict())) {
                wrapper.eq("district", addressDO.getDistrict());
            }
            if (StrUtil.isNotBlank(addressDO.getAddressDetail())) {
                wrapper.like("address_detail", addressDO.getAddressDetail());
            }
        }
        addressService.page(page, wrapper);
        long total = page.getTotal();
        List<AddressDO> records = page.getRecords();
        Map map = new HashMap<>(4);
        map.put("current", current);
        map.put("limit", limit);
        map.put("total", total);
        map.put("records", records);
        return R.ok(map);
    }

    /**
     * 用户前端以及后台管理端添加用户地址信息
     * 1. 先通过用户控制层获得用户部分信息（用户ID，用户姓名，用户性别，用户电话），作为冗余字段（后面存储在订单和配送详情里面）
     * 2. 然后封装地址信息（将用户详细地址信息（省市区详细地址的拼接）转换为经纬度信息提取出来
     * 3. 用户信息服务层将封装好的用户地址信息存入用户地址表中
     * 4. 判断用户是否将这个地址设为默认地址，如果是的话，更新用户除此地址外所有的地址列表的默认地址这一字段为非默认
     * @param addressDO
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "添加地址信息")
    @PostMapping("/save")
    public R save(@RequestBody AddressDO addressDO) throws Exception {

        // 判断详细地址是否为空
        if (StrUtil.isBlank(addressDO.getAddressDetail())) {
            R result = R.failed("详细地址为空");
            result.setCode(520);
            return result;
        }

        // 同步更新用户信息
        try {
            if (ObjectUtil.isNotNull(addressDO.getUserId())) {
                Thread thread = new Thread(() -> {
                    UserDO userDO = userService.getById(addressDO.getUserId());
                    addressDO.setUserName(userDO.getUserName());
                    addressDO.setSex(userDO.getSex());
                    addressDO.setPhone(userDO.getPhone());
                });
                thread.start();
                thread.join();
            }
        } catch (Exception e) {
            log.error("线程运行异常");
        }

        // 封装经纬度信息
        StringBuffer sb = new StringBuffer();
        sb.append(addressDO.getProvince()).append(addressDO.getCity())
                .append(addressDO.getDistrict()).append(addressDO.getAddressDetail());
        String addressInfo = sb.toString();
        String location = getLocation(addressInfo);
        String[] strings = location.split(",");
        String longitude = strings[0];
        String latitude = strings[1];
        addressDO.setLongitude(longitude);
        addressDO.setLatitude(latitude);

        boolean flag = addressService.save(addressDO);

        // 判断是否设置为默认地址
        try {
            if (ObjectUtil.isNotNull(addressDO.getAddressDefault()) && addressDO.getAddressDefault().equals("1")) {
                Thread thread = new Thread(() -> {
                    UpdateWrapper<AddressDO> wrapper = new UpdateWrapper<>();
                    wrapper.ne("address_id", addressDO.getAddressId())
                            .eq("user_id", addressDO.getUserId())
                            .set("address_default", 0);
                    addressService.update(wrapper);
                });
                thread.start();
                thread.join();
            }
        } catch (Exception e) {
            log.error("线程运行异常");
        }

        if (flag) {
            return R.ok("后台添加地址信息成功");
        } else {
            return R.failed("后台添加地址信息失败");
        }
    }

    @ApiOperation(value = "删除地址信息")
    @PostMapping("/remove/{id}")
    public R remove(@PathVariable Long id) {
        boolean flag = addressService.removeById(id);
        if (flag) {
            return R.ok("后台删除id为" + id +"的地址信息成功");
        } else {
            return R.failed("后台删除地址信息失败");
        }
    }

    /**
     * 更新用户地址信息
     * 用户前端或者后台管理端修改省、市、区、详细地址、是否为默认地址信息
     * 1. 封装经纬度信息（将详细地址（由省、市、区、详细地址拼接）转换为经纬度信息）
     * 2. 更新用户地址信息
     * 3. 判断用户是否将这个地址设为默认地址，如果是的话，更新用户除此地址外所有的地址列表的默认地址这一字段为非默认
     * @param addressDO
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "更新地址信息")
    @PostMapping("update")
    public R update(@RequestBody AddressDO addressDO) throws Exception {

        // 判断详细地址是否为空
        if (StrUtil.isBlank(addressDO.getAddressDetail())) {
            R result = R.failed("详细地址为空");
            result.setCode(520);
            return result;
        }

        // 封装经纬度信息
        StringBuffer sb = new StringBuffer();
        sb.append(addressDO.getProvince()).append(addressDO.getCity())
                .append(addressDO.getDistrict()).append(addressDO.getAddressDetail());
        String addressInfo = sb.toString();
        String location = getLocation(addressInfo);
        String[] strings = location.split(",");
        String longitude = strings[0];
        String latitude = strings[1];
        addressDO.setLongitude(longitude);
        addressDO.setLatitude(latitude);

        boolean flag = addressService.updateById(addressDO);

        // 判断是否设置为默认地址
        try {
            if (ObjectUtil.isNotNull(addressDO.getAddressDefault()) && addressDO.getAddressDefault().equals("1")) {
                Thread thread = new Thread(() -> {
                    UpdateWrapper<AddressDO> wrapper = new UpdateWrapper<>();
                    wrapper.ne("address_id", addressDO.getAddressId())
                            .eq("user_id", addressDO.getUserId())
                            .set("address_default", 0);
                    addressService.update(wrapper);
                });
                thread.start();
                thread.join();
            }
        } catch (Exception e) {
            log.error("线程运行异常");
        }

        if (flag) {
            return R.ok("后台更新id为" + addressDO.getAddressId() + "的地址信息成功");
        } else {
            return R.failed("后台更新地址信息失败");
        }
    }

    @ApiOperation(value = "批量删除用户地址信息")
    @PostMapping("/remove-ids/{ids}")
    public R deleteBatchIds(@PathVariable("ids")String[] ids) {
        List<String> list = Arrays.asList(ids);
        boolean flag = addressService.removeByIds(list);
        if (flag) {
            return R.ok("批量删除用户地址信息成功");
        } else {
            return R.failed("批量删除用户地址信息失败");
        }
    }

    @ApiOperation(value = "通过id查找用户地址信息")
    @GetMapping("/get-by-id/{id}")
    public R getByShopId(@PathVariable Long id) {
        AddressDO addressDO = addressService.getById(id);
        if (ObjectUtil.isNotNull(addressDO)) {
            return R.ok(addressDO);
        } else {
            return R.failed("未找到id为" + id + "的用户地址信息");
        }
    }

    /**
     * 通过用户ID获取用户地址列表
     * 依次根据是否为默认地址、更新时间倒序，地址ID升序进行排序
     * @param id 用户ID
     * @return
     */
    @ApiOperation(value = "通过用户id查询用户地址列表")
    @GetMapping("/list-by-user/{id}")
    public R listByUserId(@PathVariable Long id) {
        QueryWrapper<AddressDO> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", id);
        wrapper.orderByDesc("address_default");
        wrapper.orderByDesc("update_time");
        wrapper.orderByAsc("address_id");
        List<AddressDO> list = addressService.list(wrapper);
        return R.ok(list);
    }

    /**
     * 调用高德开放平台API（每日有限额）进行的定位，获取经纬信息
     * @param addressInfo 地址详细信息（已进行省、市、区、详细地址拼接的信息）
     * @return "经度,纬度"（保留小数点后六位）
     * @throws Exception
     */
    private String getLocation(String addressInfo) throws Exception {
        String url = AddressConstant.GEO_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(2);
        map.put("key", key);
        map.put("address", addressInfo);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        String location = jsonObject.getJSONArray("geocodes").getJSONObject(0).getString("location");
        return location;
    }

    /**
     * 注：address为中文地址，格式为国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦
     * @param address 拼接好的省市区详细地址
     * @return
     * @throws Exception
     * @description: 高德第三方接口，项目中已使用getLocation()函数替代
     */
    @ApiOperation(value = "获取当前位置经纬度")
    @GetMapping("/geo")
    public JSONObject geo(@RequestParam String address) throws Exception {
        String url = AddressConstant.GEO_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(2);
        map.put("key", key);
        map.put("address", address);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }

    /**
     * 注：location例子: String location = "115.904439,28.673854";
     * @param location
     * @return
     * @throws Exception
     * @description: 高德第三方接口，通过高德地图的经纬度信息转换为详细地址信息
     */
    @ApiOperation(value = "获取当前位置（通过高德地图的经纬度）")
    @GetMapping("/regeo")
    public JSONObject regeo(@RequestParam String location) throws Exception {
        String url = AddressConstant.REGEO_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(2);
        map.put("key", key);
        map.put("location", location);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }

    /**
     * 注：例子String origin = "115.904439,28.673854" String destination = "115.924028,28.674246"
     * @param origin
     * @param destination
     * @return
     * @throws Exception
     * @description: 高德第三方接口，可惜电动车规划，只有字符串，无法实时通知骑手，后面使用了直接跳转地图应用解决导航的问题
     */
    @ApiOperation(value = "获取电动车路线规划")
    @GetMapping("/direction")
    public JSONObject direction(@RequestParam String origin, @RequestParam String destination) throws Exception {
        String url = AddressConstant.DIRECTION_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(3);
        map.put("key", key);
        map.put("origin", origin);
        map.put("destination", destination);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }

    /**
     * 注：city是citycode、adcode，不支持县级市。
     * @param keywords
     * @param city
     * @param location
     * @return
     * @throws Exception
     * @description: 高德第三方接口，这个本来是想实现离用户最近的，同城的商家搜索功能，
     *              但是发现没有注册的商家也会出现在内，就挺尴尬的，而且现在商家基数不多，
     *              以后如果要做的话，可以看一下是否商家在数据库里面就行了
     */
    @ApiOperation(value = "获取输入提示")
    @GetMapping("/inputtips")
    public JSONObject inputtips(@RequestParam String keywords, @RequestParam String city,
                                @RequestParam String location) throws Exception {
        String url = AddressConstant.INPUTTIPS_API;
        String key = AddressConstant.REQUEST_KEY;
        Map<String, Object> map = new HashMap<>(4);
        map.put("key", key);
        map.put("keywords", keywords);
        map.put("city", city);
        map.put("location", location);

        String result = "";
        try {
            result = HttpUtil.get(url, map);
        } catch (Exception e) {
            throw new Exception("第三方接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject;
    }
}
